import * as THREE from "three"
import { v1, v2, v3 } from "./roomJson"
import { textureBaseUrl } from './createModel'
// import "./three.min.js"

type optionsType = Array<THREE.Mesh>

const rittalSize = {
    width: 60, //机柜的宽度
    height: 170, //机柜的高度
    len: 80, // 机柜的长度
}
// 每个u位的尺寸(机柜有42个u位) 整体距离底部10 每个间隔为2 高度为3
const bitConfig = {
    ...rittalSize,
    height: 3, //高度
    bottom: 10, // 距离底部的距离
    margin: 2, //间隔
}

// 温度分布图的配置
const heatConfig = {
    radius: 60, //半径
    interval: 50
}


export class EditModel{
    meshList: optionsType
    materialList: any[] //默认的材质
    tempMeshList: Array<THREE.LineSegments|THREE.Mesh> //临时状态的线框模型和内嵌模型
    constructor(options:optionsType) {
        this.meshList = options
        this.materialList = []
        options.forEach(ele=>{
            this.materialList.push(ele.material)
        })
        this.tempMeshList = []
    }

    /**切换空间的展示状态
     * 
     * @param type false表示切回默认状态，true表示切位空间状态
     */
    spaceChange(scene:THREE.Scene, type=false) {
        if(type===false) {
            this.meshList.forEach((mesh,index)=>{
                mesh.visible = true
            })
            this.tempMeshList.forEach(mesh=>{
                scene.remove(mesh)
            })
            this.tempMeshList = []
            return
        }

        const write_texture = new THREE.TextureLoader().load( `${textureBaseUrl}/png/write.png` );
        let out_material = new THREE.MeshBasicMaterial({ map: write_texture, transparent: true, opacity: 0.1})

        let insert_material = new THREE.MeshBasicMaterial({ color: 0xFBDAFD, transparent: true })
        this.meshList.forEach((mesh:any)=>{

            mesh.visible = false

            // 外套模型
            let out_mesh = mesh.clone()
            out_mesh.visible = true
            out_mesh.name = ""
            out_mesh.material = out_material
            this.tempMeshList.push(out_mesh)

            // 线框模型
            var edges = new THREE.EdgesGeometry(mesh.geometry);
            const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xAF47DF, linewidth: 5 } ) );
            line.position.x = mesh.position.x
            line.position.y = mesh.position.y
            line.position.z = mesh.position.z
            this.tempMeshList.push(line)

            // 内嵌模型
            const parameters = mesh.geometry.parameters
            let x = parameters.width-2
            let y = parameters.height * 0.8
            let z = parameters.depth-2

            let meshY = parameters.height
            let insert_geometry = new THREE.BoxGeometry(x, y, z)
            let insert_mesh = new THREE.Mesh(insert_geometry, insert_material)
            insert_mesh.position.set(
                mesh.position.x,
                mesh.position.y - (meshY - y)/2,
                mesh.position.z
            )
            this.tempMeshList.push(insert_mesh)
        })
        this.tempMeshList.forEach(mesh=>{
            scene.add(mesh)
        })
    }
    
    /**切换功耗的展示状态 */
    powerwasteChange(scene:THREE.Scene, type=false) {
        if(type===false) {
            this.meshList.forEach((mesh,index)=>{
                mesh.visible = true
            })
            this.tempMeshList.forEach(mesh=>{
                scene.remove(mesh)
            })
            this.tempMeshList = []
            return
        }

        let out_material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.2})
        let insert_material = new THREE.MeshBasicMaterial({ color: 0xB0E44B })
        this.meshList.forEach((mesh:any)=>{

            // 外套模型
            let out_mesh = mesh.clone()
            out_mesh.visible = true
            out_mesh.name = ""
            out_mesh.material = out_material
            this.tempMeshList.push(out_mesh)

            // 线框模型
            var edges = new THREE.EdgesGeometry(mesh.geometry);
            const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x407A07, linewidth: 5 } ) );
            line.position.x = mesh.position.x
            line.position.y = mesh.position.y
            line.position.z = mesh.position.z
            mesh.visible = false
            this.tempMeshList.push(line)

            // 内嵌模型
            const parameters = mesh.geometry.parameters
            let x = parameters.width-2
            let y = parameters.height * 0.8
            let z = parameters.depth-2

            let meshY = parameters.height
            let insert_geometry = new THREE.BoxGeometry(x, y, z)
            let insert_mesh = new THREE.Mesh(insert_geometry, insert_material)
            insert_mesh.position.set(
                mesh.position.x,
                mesh.position.y - (meshY - y)/2,
                mesh.position.z
            )
            this.tempMeshList.push(insert_mesh)
        })
        this.tempMeshList.forEach(mesh=>{
            scene.add(mesh)
        })
    }

    /**切换承重的展示状态
     * 
     * @param scene 
     * @param type 
     */
    bearingChange(scene:THREE.Scene, type=false) {
        if(type===false) {
            this.meshList.forEach((mesh,index)=>{
                mesh.visible = true
            })
            this.tempMeshList.forEach(mesh=>{
                scene.remove(mesh)
            })
            this.tempMeshList = []
            return
        }

        let success_material = new THREE.MeshBasicMaterial({ color: 0x5FD631, transparent:true, opacity: 0.8 })
        let info_material = new THREE.MeshBasicMaterial({ color: 0x4C96FF, transparent:true, opacity: 0.8 })
        let waring_material = new THREE.MeshBasicMaterial({ color: 0xFFB33A, transparent:true, opacity: 0.8 })
        let error_material = new THREE.MeshBasicMaterial({ color: 0xFF3330, transparent:true, opacity: 0.8 })
        this.meshList.forEach((mesh:any)=>{

            mesh.visible = false

            const percent = Math.random()||0.1
            // 内嵌模型
            const parameters = mesh.geometry.parameters
            let x = parameters.width
            let y = parameters.height * percent
            let z = parameters.depth

            let insert_material = success_material
            if(percent > 0.9) {
                insert_material = error_material
            } else if (percent > 0.75) {
                insert_material = waring_material
            } else if (percent > 0.5) {
                insert_material = info_material
            } else {
                insert_material = success_material
            }
            let meshY = parameters.height
            let insert_geometry = new THREE.BoxGeometry(x, y, z)
            let insert_mesh = new THREE.Mesh(insert_geometry, insert_material)
            insert_mesh.position.set(
                mesh.position.x,
                mesh.position.y - (meshY - y)/2,
                mesh.position.z
            )
            this.tempMeshList.push(insert_mesh)
        })
        this.tempMeshList.forEach(mesh=>{
            scene.add(mesh)
        })
    }

    /**切换u位的展示状态 */
    bitChange(scene:THREE.Scene, type=false, infoList:any[]=[]) {
        if(type===false) {
            this.meshList.forEach((mesh)=>{
                mesh.visible = true
            })
            this.tempMeshList.forEach(mesh=>{
                scene.remove(mesh)
            })
            this.tempMeshList = []
            return
        }

        let bit_material = new THREE.MeshBasicMaterial({ color: 0xB0E44B, transparent:true, opacity: 0.95 })
        let out_material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.4})

        let bitList = [
            { start: 10, len: 4 },
            { start: 20, len: 4 },
            { start: 30, len: 4 },
        ]

        // 相对与机柜的中心点来讲第一个u位的中心点在y轴上的坐标
        const urry = -1 * (rittalSize.height - bitConfig.height) / 2 + bitConfig.bottom
        this.meshList.forEach((mesh:any)=>{
            mesh.visible = false
            let mesh_x = mesh.position.x
            let mesh_y = mesh.position.y
            let mesh_z = mesh.position.z
            let temp_material = out_material.clone()
            // 外套模型
            let out_mesh = mesh.clone()
            out_mesh.visible = true
            out_mesh.name = "机柜"
            out_mesh.material = temp_material
            this.tempMeshList.push(out_mesh)

            // 线框模型
            var edges = new THREE.EdgesGeometry(mesh.geometry);
            const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xAF47DF, linewidth: 5 } ) );
            line.position.x = mesh_x
            line.position.y = mesh_y
            line.position.z = mesh_z
            this.tempMeshList.push(line)
            const cabinetid = mesh.userData.cabinetid
            let a = infoList.find(ele=>{ return (cabinetid == ele.cabinetid) })
            bitList = []
            if(a) {
                bitList = a.assetList.map((ele:any)=>{
                    return {
                        start: Number(ele.assetBeginU),
                        len: Number(ele.assetEndU) - Number(ele.assetBeginU)
                    }
                })
            }

            // 进行u位的创建
            bitList.forEach(bit=>{
                const height = bit.len * (bitConfig.height + bitConfig.margin) - bitConfig.margin
                const y = urry + bit.start * (bitConfig.height + bitConfig.margin) - bitConfig.margin
                let bit_geometry = new THREE.BoxGeometry(bitConfig.width, height, bitConfig.len)
                let bit_mesh = new THREE.Mesh(bit_geometry, bit_material)
                bit_mesh.name = "u位"
                bit_mesh.position.set(mesh_x, mesh_y + y, mesh_z)
                this.tempMeshList.push(bit_mesh)
            })

        })
        this.tempMeshList.forEach(mesh=>{
            scene.add(mesh)
        })
        return
    }

    /**切换温度的展示状态 */
    humidityChange(scene:THREE.Scene, type=false) {

        if(type===false) {
            this.tempMeshList.forEach(mesh=>{
                scene.remove(mesh)
            })
            this.tempMeshList = []
            return
        }

        this.tempMeshList = []
        let points:any = createPointList(this.meshList)
        this.tempMeshList.push(points)
        scene.add(points)
    }


}

// ********************使用精灵图绘制空间温度***********



// ********************END****************************

// function createPointList() {
//     const point_material = new THREE.PointsMaterial({ size: 2, vertexColors: true, transparent: true, opacity: 0.5})
//     // 创建粒子数据
//     const maxParticles = 300000;
//     const particlePositions = new Float32Array(maxParticles * 3); // 每个粒子有3个浮点数来定义位置
//     const particleColors = new Float32Array(maxParticles * 3); // 每个粒子有3个浮点数来定义颜色（如果材质color值未设置）

//     for(let i = 0; i < maxParticles; i++) {
//         // 随机位置
//         particlePositions[i * 3] = Math.random() * 1000 - 1000/2;
//         particlePositions[i * 3 + 1] = Math.random() * 100 - 100/2;
//         particlePositions[i * 3 + 2] = Math.random() * 1000 - 1000/2;

//         // 随机颜色（如果需要）
//         let color = new THREE.Color()
//         const vx = Math.random() * 1;
//         const vy = Math.random() * 1;
//         const vz = Math.random() * 1;

//         color.setRGB( vx, vy, vz, THREE.SRGBColorSpace );

//         particleColors[i * 3] = color.r;
//         particleColors[i * 3 + 1] = color.g;
//         particleColors[i * 3 + 2] = color.b;


//     }

//     // 创建粒子属性缓存
//     const particleBuffer = new THREE.BufferAttribute(particlePositions, 3);
//     const colorBuffer = new THREE.BufferAttribute(particleColors, 3);
//     console.log("particleBuffer",particleBuffer)
//     console.log("colorBuffer",colorBuffer)


//     // 创建粒子系统
//     let point_geometry = new THREE.BufferGeometry()
    
//     point_geometry.setAttribute('position', particleBuffer)
//     point_geometry.setAttribute('color', colorBuffer)
//     point_geometry.computeBoundingSphere();

//     const points = new THREE.Points( point_geometry, point_material);
//     return points

// }

/**创建粒子特效
 * 
 * @param list 机柜列表
 */
function createPointList(list:THREE.Mesh[]) {

    let arr = list.slice()
    const sigma = estimateSigma(50, 25, 2)

    const point_material = new THREE.PointsMaterial({ size: 2, vertexColors: true, transparent: true, opacity: 0.8})
    const maxParticles = 600000
    let positionArr:number[] = []
    let colorArr:number[] = []
    let y_value = v3 / 2
    for(let i = 0; i < maxParticles; i++) {
        let x = Math.random() * v1 - v1/2
        let y = Math.random() * y_value - y_value/2
        let z = Math.random() * v2 - v2/2
        positionArr.push(x)
        positionArr.push(y)
        positionArr.push(z)

        let minDis = getMinDic(arr, x, z)
        let temperature = calculateTemperature(50, minDis/100, sigma)
        let color = getColorByTemperature(temperature)
        colorArr.push(color.r)
        colorArr.push(color.g)
        colorArr.push(color.b)
    }

    const positionBuffer = new THREE.BufferAttribute(new Float32Array(positionArr), 3);
    const colorBuffer = new THREE.BufferAttribute(new Float32Array(colorArr), 3);

    let point_geometry = new THREE.BufferGeometry()
    point_geometry.setAttribute('position', positionBuffer)
    point_geometry.setAttribute('color', colorBuffer)
    point_geometry.computeBoundingSphere();

    const points = new THREE.Points( point_geometry, point_material);
    return points
}

/**获取距离最近的机房
 * 
 * @param list 
 * @param x 
 * @param z 
 * @returns 
 */
function getMinDic(list:THREE.Mesh[], x:number , z:number) {
    list.sort((a,b) => {
        return Math.sqrt((a.position.x - x)**2 + (a.position.z - z) **2) - Math.sqrt((b.position.x - x)**2 + (b.position.z - z) **2)
    })
    if(list.length < 0) {
        return 0
    } else {
        let ele = list[0]
        return Math.sqrt((ele.position.x - x)**2 + (ele.position.z - z) **2)
    }
}

/**获取位置温度
 * 
 * @param T0 热源温度
 * @param dis 水平距离
 * @param sigma 热扩散的标准差
 * @returns 该位置的温度
 */
function calculateTemperature(T0:number, dis:number, sigma:number=10) {
    const temperature = T0 * Math.exp(-(dis ** 2) / (2 * sigma ** 2));
    return temperature;
}

/**根据温度生成对应颜色
 * 
 * @param temperature 温度值
 * @returns 
 */
function getColorByTemperature(temperature:number) {
    // 确保温度在一个合理的范围内
    temperature = Math.max(25, Math.min(60, temperature));

    // 等级1 8afc00 -> rgb(138, 252, 0)
    // 等级2 b3fc00 -> rgb(179, 252, 0)
    // 等级3 fce700 -> rgb(252, 231, 0)
    // 等级4 fc9d00 -> rgb(252, 157, 0)
    // 等级5 fc6700 -> rgb(252, 103, 0)
    // 等级6 6b0606 -> rgb(107, 6, 6)
    let r,g,b;
    if(temperature < 30) {
        return new THREE.Color(0x82d8f8)
    } else if (temperature < 35) {
        let t = (temperature - 30) / 5;
        r = 138 + t * (179 - 138);
        g = 252
        b = 0
    } else if (temperature < 40) {
        let t = (temperature - 35) / 5;
        r = 179 + t * (252 - 179);
        g = 252 + t * (231 - 252);
        b = 0
    } else if (temperature < 45) {
        let t = (temperature - 40) / 5;
        r = 252;
        g = 231 + t * (157 - 231);
        b = 0
    } else if (temperature < 50) {
        let t = (temperature - 45) / 5;
        r = 252;
        g = 157 + t * (103 - 157);
        b = 0
    } else {
        let t = (temperature - 50) / 10;
        r = 252 + t * (107 - 252);
        g = 103 + t * (6 - 103);
        b = t * (6)
    }

    return new THREE.Color(`rgb(${Math.round(r)},${Math.round(g)},${Math.round(b)})`);

    
}

/**获取常温下热扩散系数
 * 
 * @param T0 热源温度
 * @param Tambient 环境温度
 * @param d 从热源降低到环境温度需要的距离
 * @returns 
 */
function estimateSigma(T0:number, Tambient:number, d:number) {
    const sigma = Math.sqrt(d * d / (2 * Math.log(T0 / Tambient)));
    return sigma;
}
   


// **********************以下代码为了绘制热力图*******************

//绘制辐射圆
let drawCircular=(context:any,opts:any)=>{
    let {x,y,radius,weight}=opts;

    radius= parseInt((radius * weight)+"");//计算出实际的辐射圆

    // 创建圆设置填充色
    let rGradient = context.createRadialGradient(x, y, 0, x, y, radius);
    rGradient.addColorStop(0, "rgba(0, 1, 0, 1)");
    rGradient.addColorStop(1, "rgba(1, 0, 0, 0)");
    context.fillStyle = rGradient;

    // 设置globalAlpha
    context.globalAlpha = weight;
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI);
    context.closePath();

    context.fill();// 填充

}

//随机给出温度值  储存在2维数组
let getTemperature=()=>{
    var  temperatureArray=new Array();
    for(let i=0;i<v1/heatConfig.interval;i++){
        temperatureArray[i]=new Array();
        for(let j=0;j<v2/heatConfig.interval;j++) {
            temperatureArray[i][j] = 20;
        }
    }
    return temperatureArray;
}


//获取温度点的XY坐标
let getPositionXY=(i:number,j:number)=>{
    let positionX=[5,20,35,50,65,80,95,80,90];
    let positionY=[5,20,35,50,65,80,95,80,90];
    return {
        x:positionX[i],
        y:positionY[j]
    }
    
}

let createPalette=()=>{
    //颜色条的颜色分布
    let colorStops = {
        0: "#0ff",
        0.4: "#0f0",
        0.8: "#ff0",
        1: "#f00"
    };
    //颜色条的大小
    let width = 256, height = 1;
    // 创建canvas
    let paletteCanvas = document.createElement("canvas");
    paletteCanvas.width = width;
    paletteCanvas.height = height;
    let ctx = paletteCanvas.getContext("2d");
    if(!ctx) return { 
        canvas:paletteCanvas, 
        pickColor: function (position:any) {
            return imageData.slice(position * 4, position * 4+3 )
        } 
    };
    // 创建线性渐变色
    let linearGradient = ctx.createLinearGradient(0, 0, width, 0);
    for (const key in colorStops) {
        linearGradient.addColorStop(Number(key), colorStops[key as "0"]);
    }

    // 绘制渐变色条
    ctx.fillStyle = linearGradient;
    ctx.fillRect(0, 0, width, height);

    let imageData = ctx.getImageData(0, 0, width, height).data;// 读取像素值

    return {
        canvas: paletteCanvas,
        pickColor: function (position:any) {
            return imageData.slice(position * 4, position * 4+3 )
        }
    }
}

let heatMap=(width:number,height:number, positionList:Array<any>, weightList:Array<number>)=>{
    let canvas = document.createElement("canvas");
    canvas.width=width;
    canvas.height=height;
    let context = canvas.getContext("2d");
    let tenperature=getTemperature();
    console.log(tenperature)

    if(!context) return canvas;

    positionList.forEach((pos,index)=>{
        let weight=weightList[index]/30;
        drawCircular(context,{
            x: pos.x,
            y: pos.y,
            radius: heatConfig.radius,
            weight:weight
        })
    })
    
    let palette = createPalette();
    document.body.appendChild(palette.canvas);
    let imageData = context.getImageData(0, 0, width, height);
    let data=imageData.data;

    for (let i = 3; i < data.length; i += 4) {//根据画面数据绘制颜色
        let alpha = data[i];
        let color = palette.pickColor(alpha);
        data[i - 3] = color[0];
        data[i - 2] = color[1];
        data[i - 1] = color[2];
    }

    for(var i = 0; i < imageData.data.length; i += 4) {// 背景设置成青色
        if(imageData.data[i + 3] == 0) {
            imageData.data[i] = 0;
            imageData.data[i + 1] = 255;
            imageData.data[i + 2] = 255;
            imageData.data[i + 3] = 255;
        }
    }
    context.putImageData(imageData, 0, 0);//设置画面数据
    return canvas;
}


let heatMap_old=(width:number,height:number)=>{
    let canvas = document.createElement("canvas");
    canvas.width=width;
    canvas.height=height;
    let context = canvas.getContext("2d");
    let tenperature=getTemperature();
    console.log(tenperature)

    if(!context) return canvas;

    for(let i=0;i<v1/heatConfig.interval;i++) {
        for (let j = 0; j < v2/heatConfig.interval; j++) {
            let weight=tenperature[i][j]/30;  //计算出当前温度占标准温度的权值
            drawCircular(context,{
                x: (i-1) * heatConfig.interval + heatConfig.interval,
                y: (j-1) * heatConfig.interval + heatConfig.interval,
                radius: heatConfig.radius,
                weight:weight
            })
        }
    }
    let palette = createPalette();
    document.body.appendChild(palette.canvas);
    let imageData = context.getImageData(0, 0, width, height);
    let data=imageData.data;

    for (let i = 3; i < data.length; i += 4) {//根据画面数据绘制颜色
        let alpha = data[i];
        let color = palette.pickColor(alpha);
        data[i - 3] = color[0];
        data[i - 2] = color[1];
        data[i - 1] = color[2];
    }

    for(var i = 0; i < imageData.data.length; i += 4) {// 背景设置成青色
        if(imageData.data[i + 3] == 0) {
            imageData.data[i] = 0;
            imageData.data[i + 1] = 255;
            imageData.data[i + 2] = 255;
            imageData.data[i + 3] = 255;
        }
    }
    context.putImageData(imageData, 0, 0);//设置画面数据
    return canvas;
}




